#include <list>
#include <string>
#include <iostream>
#include <utility>

using namespace std;

class Subject;

class Observer;

class Observer {
private:
    string name;

protected:
    Subject *subject;

public:
    Observer(string name, Subject *subject) : name(std::move(name)), subject(subject) {}

    const string &getName() const { return name; }

public:
    virtual void update() = 0;
};

class Subject {
protected:
    int state = 0;

    list<Observer *> observer_list;

public:
    virtual ~Subject() = default;

public:
    virtual void notify() = 0;

    virtual void attach(Observer *) = 0;

    virtual void detach(Observer *) = 0;

    virtual int getState() = 0;
};

class ObserverA : public Observer {
public:
    ObserverA(const string &name, Subject *subject) : Observer(name, subject) {}

public:
    void update() override {
        cout << getName() << " 观察到主题的更改!" << endl;
        cout << "主题的状态为: " << subject->getState() << endl;
    }
};

class ObserverB : public Observer {
public:
    ObserverB(const string &name, Subject *subject) : Observer(name, subject) {}

public:
    void update() override {
        cout << getName() << " 观察到主题的更改!" << endl;
        cout << "主题的状态为: " << subject->getState() << endl;
    }
};

class ConcreteSubject : public Subject {
public:
    ~ConcreteSubject() override {
        for (auto i = observer_list.begin(); i != observer_list.end(); ++i) {
            Observer *observer = *i;
            delete observer;
        }
    }

public:
    void notify() override {
        for (auto i = observer_list.begin(); i != observer_list.end(); ++i) {
            Observer *observer = *i;
            observer->update();
        }
    }

    void attach(Observer *observer) override {
        observer_list.push_back(observer);
        state++;
    }

    void detach(Observer *observer) override {
        observer_list.remove(observer);
        state--;
    }

    int getState() override {
        return state;
    }
};

void test01() {
    Subject *subject;
    Observer *observerA, *observerB;

    subject = new ConcreteSubject();
    observerA = new ObserverA("Blue", subject);
    observerB = new ObserverB("Yuie", subject);

    subject->attach(observerA);
    subject->notify();
    cout << "------------------------------" << endl;
    subject->attach(observerB);
    subject->notify();

    delete subject;
}

int main() {
    test01();
}